package com.telit.communicate.controller;

import com.telit.common.entity.DataReturn;
import com.telit.common.enums.ResultCode;
import com.telit.communicate.communicate.MessageProcessFactory;
import com.telit.communicate.communicate.MsgProcessPathCache;
import com.telit.communicate.communicate.ServerHandler;
import com.telit.communicate.communicate.ZookeeperRegister;
import com.telit.communicate.constant.CommunicateVariable;
import com.telit.communicate.constant.MsgSource;
import com.telit.communicate.constant.SystemName;
import com.telit.communicate.dto.MsgProcessPathDTO;
import com.telit.communicate.dto.SendMessageDTO;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import java.net.Inet4Address;
import java.util.List;
import java.util.concurrent.ExecutorService;


/**
 * @author zhouyu
 * @description 外部调用接口
 */
@RequestMapping("/msg")
@RestController
@Api(tags = "外部调用接口", description = "/msg")
public class MessageController {

    @Autowired
    private MessageProcessFactory messageProcessFactory;

    @Autowired
    private ZookeeperRegister zookeeperRegister;


    @Autowired
    private RestTemplate restTemplate;

    @Value("${server.port}")
    private int port;


    @PostMapping("/send")
    @ApiOperation("websocket推送消息")
    public DataReturn sendMsg(@Validated @RequestBody(required = true) SendMessageDTO sendMessageDTO) {
        try {
            if (sendMessageDTO.getFlag() == null || sendMessageDTO.getMsg() == null) {
                return DataReturn.failure(ResultCode.REQUEST_PARAMS_CHECK_ERROR);
            }
            String flag = sendMessageDTO.getFlag();
            if ("all".equalsIgnoreCase(flag)) {
                //发送给所有在线用户
                ServerHandler.sendMessageToAll(sendMessageDTO.getMsg());
            } else if ("allWithoutUserId".equals(flag)) {
                //发送给所有除了excludeUserId集合之外的所有在线用户
                ServerHandler.sendMessageToWithoutSpecialUsers(sendMessageDTO.getExcludeUserId(), sendMessageDTO.getMsg());
            } else if ("web".equalsIgnoreCase(flag)) {
                //发送给所有web端
                ServerHandler.sendMessageToWeb(sendMessageDTO.getMsg());
            } else if ("webWithoutUserId".equalsIgnoreCase(flag)) {
                //发送给除了excludeUserId集合之外的所有web端
                ServerHandler.sendMessageToWebWithoutSpecialUsers(sendMessageDTO.getExcludeUserId(), sendMessageDTO.getMsg());
            } else if ("webWithinUserId".equalsIgnoreCase(flag)) {
                //发送给userId集合之内的所有web端
                ServerHandler.sendMessageToWebWithinSpecialUsers(sendMessageDTO.getUserId(), sendMessageDTO.getMsg());
            } else if ("phone".equalsIgnoreCase(flag)) {
                //发送给所有安卓端
                ServerHandler.sendMessageToPhone(sendMessageDTO.getMsg());
            } else if ("special".equalsIgnoreCase(flag)) {
                //发送给特定用户
                ServerHandler.sendMessageToSpecialUsers(sendMessageDTO.getUserId(), sendMessageDTO.getMsg());
            }

            //客户端已连接
            if (CommunicateVariable.registerSuccess.get()) {
                String hostAddress = Inet4Address.getLocalHost().getHostAddress() + ":" + port;
                List<String> allServer = zookeeperRegister.getAllServer();
                allServer.remove(hostAddress);
                allServer.remove("zookeeper");
                if (!allServer.isEmpty()) {
                    //集群里还存在其他服务端
                    for (String server : allServer) {
                        String sendMsgUrl = zookeeperRegister.getSendMsgUrl(server);
                        restTemplate.postForEntity(sendMsgUrl, sendMessageDTO, SendMessageDTO.class);
                    }
                }
            }
            return DataReturn.ok("Message already send out");
        } catch (Exception e) {
            e.printStackTrace();
            return DataReturn.failure(ResultCode.SERVER_ERROR);
        }
    }


    @PostMapping("/subscribeMsgProcess")
    @ApiOperation("订阅消息处理接口")
    public DataReturn subscribeMsgProcess(@RequestBody MsgProcessPathDTO msgProcessPathDTO) {
        if (msgProcessPathDTO.getSystemName() == null || msgProcessPathDTO.getMsgSource() == null) {
            return DataReturn.failure(ResultCode.REQUEST_PARAMS_CHECK_ERROR);
        }
        //消息处理路径添加
        boolean result = MsgProcessPathCache.addProcessPath(msgProcessPathDTO);
        if (result) {
            //开启消息处理线程
            messageProcessFactory.startMessageProcess(SystemName.getSystemName(msgProcessPathDTO.getSystemName()), MsgSource.getMsgSource(msgProcessPathDTO.getMsgSource()));
            messageProcessFactory.startShutdownHookProcess(SystemName.getSystemName(msgProcessPathDTO.getSystemName()), MsgSource.getMsgSource(msgProcessPathDTO.getMsgSource()));
        }
        return DataReturn.ok();
    }

    @PostMapping("/unSubscribeMsgProcess")
    @ApiOperation("取消订阅消息处理接口")
    public DataReturn unSubscribeMsgProcess(@RequestBody MsgProcessPathDTO msgProcessPathDTO) {
        if (msgProcessPathDTO.getSystemName() == null || msgProcessPathDTO.getMsgSource() == null) {
            return DataReturn.failure(ResultCode.REQUEST_PARAMS_CHECK_ERROR);
        }
        //消息处理路径移除
        MsgProcessPathCache.removeProcessPath(msgProcessPathDTO);
        //关闭消息处理线程池
        CommunicateVariable.threadHandler.put(msgProcessPathDTO.getSystemName() + msgProcessPathDTO.getMsgSource(), false);
        ExecutorService executorService = CommunicateVariable.threadPoolHandler.remove(msgProcessPathDTO.getSystemName() + msgProcessPathDTO.getMsgSource());
        if (executorService != null) {
            executorService.shutdown();
        }
        return DataReturn.ok();
    }
}
